package com.xd.center.http.config;

import com.xd.center.http.builder.HttpBuilder;
import com.xd.center.http.builder.HttpContract;
import com.xd.center.http.builder.HttpDecoder;
import com.xd.center.http.builder.HttpEncoder;
import lombok.Data;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.util.Map;

@Data
public class HttpClientFactoryBean implements FactoryBean<Object>, ApplicationContextAware {

  private Class<?> type;
  private ApplicationContext context;
  private Map<String, String> configMap;

  @Override
  public void setApplicationContext(ApplicationContext context) throws BeansException {
    this.context = context;
  }

  @Override
  public Object getObject() {
    return HttpBuilder.init(context, type)
      .contract(new HttpContract.Default())
      .encoder(new HttpEncoder.Default())
      .decoder(new HttpDecoder.Default())
      .build();
  }

  @Override
  public Class<?> getObjectType() {
    return type;
  }

  /*class ApiContract extends Contract.Default {
    final Pattern REQUEST_LINE_PATTERN = Pattern.compile("^([A-Z]+)[ ]*(.*)$");

    public ApiContract() {
      super.registerMethodAnnotation(HttpLine.class, (ann, data) -> {

        String requestLine = ann.value();
        checkState(emptyToNull(requestLine) != null, "RequestLine annotation was empty on method %s.", data.configKey());
        Matcher requestLineMatcher = REQUEST_LINE_PATTERN.matcher(requestLine);
        if (!requestLineMatcher.find()) {
          throw new IllegalStateException(String.format("RequestLine annotation didn't start with an HTTP verb on method %s", data.configKey()));
        } else {
          data.template().method(Request.HttpMethod.valueOf(requestLineMatcher.group(1)));
          StringBuffer uri = new StringBuffer(requestLineMatcher.group(2));
          String auth = configMap.get("auth");
          if (!StringUtil.isEmpty(auth)) {
            uri.append(uri.toString().contains("?") ? "&" + auth : "?" + auth);
          }
          data.template().uri(uri.toString());
        }
        data.template().decodeSlash(ann.decodeSlash());
        data.template().collectionFormat(ann.collectionFormat());
      });
    }
  }*/
/*
  class HttpEncoder implements Encoder {

    @Override
    public void encode(Object object, Type bodyType, RequestTemplate template) {
      Map<String, Object> map = new HashMap<>();
      map.put("current", 1);
      byte[] bytes = null;
      ByteArrayOutputStream bos = new ByteArrayOutputStream();
      try {
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(JSON.parseObject(JSON.toJSONString(object), type));
        oos.flush();
        bytes = bos.toByteArray();
        oos.close();
        bos.close();
      } catch (IOException ex) {
        ex.printStackTrace();
      }

      String aa = "current=1&size=20&name=1";

      Request.Body body = Request.Body.empty();
      //Request.Body.encoded(bytes, Charset.forName("UTF-8"))
      //template.body(JSON.toJSONString(object));
      template.body(aa);
    }
  }


  class HttpDecoder implements Decoder {
    @Override
    public Object decode(Response response, Type type) throws IOException {
      if (response.body() == null) return null;
      InputStream inputStream = response.body().asInputStream();
      try {
        ByteArrayOutputStream result = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int length;
        while ((length = inputStream.read(buffer)) != -1) {
          result.write(buffer, 0, length);
        }
        String json = result.toString(StandardCharsets.UTF_8.name());

        return JSON.parseObject(json, type);
        *//*Class clazz = getClass(type);
        if (null != clazz) {
          Map<String, Object> map = JSON.parseObject(json, Map.class);
          Object dto = clazz.newInstance();
          Method initMethod = clazz.getMethod("analysis", Map.class);
          Object obj = initMethod.invoke(dto, map);
          return obj;
        } else {
          return JSON.parseObject(json, type);
        }*//*
      } catch (JsonIOException e) {
        if (e.getCause() != null && e.getCause() instanceof IOException) {
          throw IOException.class.cast(e.getCause());
        }
        throw e;
      } catch (Exception e) {
        e.printStackTrace();
      } finally {
        inputStream.close();
      }
      return null;
    }

    public Class getClass(Type type) {
      ParameterizedType parameterizedType = (ParameterizedType) type;
      Type[] types = parameterizedType.getActualTypeArguments();
      for (Type t : types) {
        if (t instanceof ParameterizedType) {
          return getClass(t);
        } else {
          Class[] cs = ((Class) t).getInterfaces();
          for (Class c : cs) {
            if (c.equals(MappingDto.class)) {
              return (Class) t;
            }
          }
        }
      }
      return null;
    }

  }*/
}
